package others;

//import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

//@Slf4j
public class CompletableFutureLearn2 {
    private static final Logger log = Logger.getLogger("jdk自带的log日志打印时，无线程名称");

    public static void main(String[] args) throws ExecutionException, InterruptedException {
//        completeTest();
//        runAsyncTest();
//        supplyAsyncTest();
//        callSupplyAsyncTest();
        thenRunTest();
    }

    public static void thenComposeTest() {
        CompletableFuture<CompletableFuture<Double>> result = getUsersDetail("asdf")
                .thenApply(user -> getCreditRating(user));
    }

    //获取用户信息详情
    static CompletableFuture<Product>  getUsersDetail(String userId) {
        return CompletableFuture.supplyAsync(() -> Product.builder().id(12345L).name("日拱一兵").build());
    }

    //获取用户信用评级
    static CompletableFuture<Double> getCreditRating(Product user) {
        return CompletableFuture.supplyAsync(() -> 123.4);
    }

    public static void thenRunTest() throws ExecutionException, InterruptedException {
        final CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(
                // 模拟远端API调用，这里只返回了一个构造的对象
                () -> Product.builder().id(12345L).name("颈椎/腰椎治疗仪").build())
                .thenAccept(product -> {
                    log.info("获取到远程API产品名称 " + product.getName());
                });
        voidCompletableFuture.get();
    }

    public static void callSupplyAsyncTest() throws ExecutionException, InterruptedException {
        CompletableFuture<String> comboText = CompletableFuture.supplyAsync(() -> {
            //可以注释掉做快速返回 start
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            log.info("赞");
            //可以注释掉做快速返回 end
            return "赞";
        })
                .thenApply(first -> {
                    log.info("在看");
                    return first + ", 在看";
                })
                .thenApply(second -> second + ", 转发");

        log.info("三连有没有？");
        log.info(comboText.get());
    }

    public static void supplyAsyncTest() throws ExecutionException, InterruptedException {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            log.info("运行在一个单独的线程当中");
            return "我有返回值";
        });

        log.info(future.get());
    }

    public static void runAsyncTest() throws ExecutionException, InterruptedException {
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            System.out.println("运行在一个单独的线程当中");
        });

        future.get();
    }

    public static void completeTest() throws ExecutionException, InterruptedException {
        CompletableFuture<String> completableFuture = new CompletableFuture<>();
        /*手动结束Future，返回指定值；避免永久阻塞*/
        completableFuture.complete("Future's Result Here Manually");
        String result = completableFuture.get();

        System.out.println(result);
    }
}

class Product {
    private long id;
    private String name;

    public Product(Builder builder) {
        this.id = builder.id;
        this.name = builder.name;
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    static Builder builder() {
        return new Builder();
    }

    static class Builder {
        private long id;
        private String name;

        public Builder id(long id) {
            this.id = id;
            return this;
        }

        public Builder name(String name) {
            this.name = name;
            return this;
        }

        public Product build() {
            return new Product(this);
        }
    }
}
